
function Promise(executor) {
    this.PromiseState = 'pending';
    this.PromiseResult = undefined;
    this.callbacks = [];
    let resolve = (value) => {
        if (this.PromiseState !== 'pending') return;
        this.PromiseState = 'fulfilled';
        this.PromiseResult = value;
        if (this.callbacks.length) {
            this.callbacks.forEach(item => {
                item.success();
            })
        }
    }
    let reject = (reason) => {
        if (this.PromiseState !== 'pending') return;
        this.PromiseState = 'rejected';
        this.PromiseResult = reason;
        if (this.callbacks.length) {
            this.callbacks.forEach(item => {
                item.fail();
            })
        }
    }
    try {
        executor(resolve, reject);
    } catch (e) {
        reject(e);
    }
}
Promise.prototype.then = function (onResolved, onRejected) {
    // 如果then成功或失败的回调没传，那么给一个默认值
    if(typeof onResolved !== 'function'){
        onResolved = v=>v;
    }
    if(typeof onRejected !== 'function'){
        onRejected = r => new Promise((resolve,reject)=>{
            reject(r);
        })
    }
    // 函数内部自己调用自己：递归调用
    return new Promise((resolve, reject) => {
        let changeState = (typeFn) => {
            setTimeout(()=>{
                let rs = typeFn(this.PromiseResult);
                if (rs instanceof Promise) {
                    rs.then(resolve, reject);
                } else {
                    resolve(rs);
                }
            })
        }
        if (this.PromiseState === 'fulfilled') {
            changeState(onResolved);
        }
        if (this.PromiseState === 'rejected') {
            changeState(onRejected);
        }
        if (this.PromiseState === 'pending') {
            this.callbacks.push({
                success: () => {
                    changeState(onResolved);
                },
                fail: () => {
                    changeState(onRejected);
                }
            })
        }
    })
}

// catch: 专门用来指定失败的回调函数
// then : 可以指定成功和失败的回调
Promise.prototype.catch = function(onRejected){
    return this.then(null,onRejected);
}

/**
 * 一定返回一个promise对象
 * 1. 参数是非Promise 那么， fulfilled， 结果值就是 参数
 * 2. 参数是promise，那么，你成功我成功，你失败我失败
 * 
 */ 

Promise.resolve = function(params){
    return new Promise((resolve,reject)=>{
        if(params instanceof Promise){
            params.then(resolve, reject);
        }else{
            resolve(params);
        }
    })
}
/**
 * Promise.reject(参数)
 *      一定返回一个失败的promise，参数就是失败promise的结果值
 * 
 */
Promise.reject = function(reason){
    return new Promise((resolve,reject)=>{
        reject(reason);
    })
}

/**
 * 1. promiseArr 是一个promise对象组成的数组
 * 如果数组中的promise都是成功的，那么all方法返回的promise也是成功的。并且成功的结果值是 promiseArr数组中成功结果值组成的数组
 * 2. promiseArr 数组中有一个promise是失败的，那么 all方法返回的就是一个失败的promise，并且失败的原因，就是promiseArr中第一个失败的promise的原因
 * 
 */
Promise.all = function(promiseArr){
    // 成功后 结果值数组
    let resultArr = [];
    // 计数器，记录有几个成功的结果已经返回，如果count值跟 promiseArr.length 长度一致，那么说明 promiseArr中都是成功的promise
    let count = 0;

    return new Promise((resolve,reject)=>{
        promiseArr.forEach((item,index)=>{
            item.then(value=>{
                //按索引存放结果值，确保与promiseArr中的promise元素位置关系一一对应
                resultArr[index] = value;
                // 如果使用push，那么有异步的情况，顺序会乱
                // resultArr.push(value);
                count++;
                // 如果count值和数组长度相等，所有所有成功promise的结果值已经返回。说明所有的promise都是成功的promise，那么all方法的返回值就是一个成功的promise
                if(count === promiseArr.length){
                    resolve(resultArr)
                }
            },reason=>{
                // 有一个失败的，就全部失败
                reject(reason);
            })
        })
    })
}

/**
 * Promise.race([p1,p2,p3])
 *    谁先回来，我的状态和结果就跟谁一致
 */

Promise.race = function(promiseArr){
    return new Promise((resolve,reject)=>{
        // 遍历promise数组
        promiseArr.forEach(item=>{
            item.then(v=>{
                resolve(v);
            },r=>{
                reject(r);
            })
        })
    })
}

// 不是照着敲，搞懂逻辑思路